package com.gitee.wsl.struct.compare

import timber.log.Timber

abstract class ExtensibleSortingComparator<T>(
    protected val reverseOrder: Boolean,
    protected val priorityItemsFirst: Boolean
) : Comparator<T?> {

    abstract fun compareItems(item1: T, item2: T): Int

    abstract fun isPriorityItem(item: T): Boolean

    override fun compare(a: T?, b: T?): Int {

        if (null == a || null == b)
            return compareWithNull(a, b)

        return when {
            priorityItemIsFirst(a,b) -> comparePriorityAndOrdinaryItem(a,b)
            priorityItemIsSecond(a,b) -> compareOrdinaryAndPriorityItem(a,b)
            else -> compareOneTypeItems(a,b)
        }
    }

    private fun compareWithNull(item1: T?, item2: T?): Int {
        return when {
            (null == item1) -> 1
            (null == item2) -> -1
            else -> {
                Timber.e("One or both arguments of method must be NULL (arg1: $item1, arg2: $item2")
                return 0
            }
        }
    }


    private fun comparePriorityAndOrdinaryItem(priorityItem: T, ordinaryItem: T): Int {
        return if (priorityItemsFirst) return -1
        else compareOneTypeItems(priorityItem,ordinaryItem)
    }


    private fun compareOrdinaryAndPriorityItem(ordItem: T, prItem: T): Int {
        return if (priorityItemsFirst) 1
        else compareOneTypeItems(ordItem,prItem)
    }


    private fun compareOneTypeItems(item1: T, item2: T): Int {
        return compareItems(item1, item2).let {
            if (reverseOrder) it * reverseMultiplier()
            else it
        }
    }


    private fun reverseMultiplier(): Int = if (reverseOrder) -1 else 1

    private fun priorityItemIsFirst(item1: T, item2: T): Boolean = isPriorityItem(item1) && !isPriorityItem(item2)

    private fun priorityItemIsSecond(item1: T, item2: T): Boolean = !isPriorityItem(item1) && isPriorityItem(item2)

}